﻿using System;
using System.Collections.Generic;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading;

namespace ShinePipe
{
    /// <summary>
    /// 命名管道客户端
    /// </summary>
    public class ShineNamePipeClient
    {
        private const int CONNECT_TIMEOUT = 2000;

        /// <summary>
        /// 接收事件
        /// </summary>
        public event ShinePipeRecvEventHandler ShinePipeRecvEvent;

        /// <summary>
        /// 关闭事件
        /// </summary>
        public event ShinePipeCloseEventHandler ShinePipeCloseEvent;

        /// <summary>
        /// 测试使用
        /// </summary>
        public event ShinePipeDebugEventHandler ShinePipeDebugEvent;

        /// <summary>
        /// 管道客户端
        /// </summary>
        private NamedPipeClientStream _pipeClient;

        /// <summary>
        /// 启动命名管道
        /// </summary>
        /// <param name="p_pipeName"></param>
        public bool Start(string p_pipeName)
        {
            try
            {
                _pipeClient = new NamedPipeClientStream("127.0.0.1", p_pipeName, PipeDirection.InOut, PipeOptions.Asynchronous, System.Security.Principal.TokenImpersonationLevel.Identification, System.IO.HandleInheritability.None);
                if (ShinePipeDebugEvent != null)
                {
                    ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"客户端管道 创建成功" });
                }

                if (!Connect())
                {
                    return false;
                }
                ReadWork();
                return true;
            }
            catch
            {
                if (ShinePipeDebugEvent != null)
                {
                    ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"客户端管道 创建失败" });
                }
                throw;
            }
        }

        /// <summary>
        /// 关闭管道
        /// </summary>
        public void Stop()
        {
            if (ShinePipeDebugEvent != null)
            {
                ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"客户端管道 申请 关闭" });
            }
            if (_pipeClient.IsConnected)
            {
                Write(@"NamePipeCloseReq");
            }
            else
            {
                Dispose();
            }

        }

        /// <summary>
        /// 释放所有资源
        /// </summary>
        private void Dispose()
        {
            _pipeClient.Close();
            if (ShinePipeDebugEvent != null)
            {
                ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"客户端管道 关闭" });
            }

            _pipeClient.Dispose();
            _pipeClient = null;
            if (ShinePipeDebugEvent != null)
            {
                ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"客户端管道 释放" });
            }

            if (ShinePipeCloseEvent != null)
            {
                ShinePipeCloseEvent(this, new ShinePipeCloseEventArgs() { Message = @"" });
            }
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="p_msg"></param>
        public void Write(string p_msg)
        {
            if (ShinePipeDebugEvent != null)
            {
                ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"客户端管道 准备发送：" + p_msg });
            }

            if (_pipeClient != null && _pipeClient.IsConnected)
            {
                byte[] bytesArray = System.Text.Encoding.Unicode.GetBytes(p_msg);
                _pipeClient.BeginWrite(bytesArray, 0, bytesArray.Length,
                    ar =>
                    {
                        if (ar.IsCompleted)
                        {
                            try
                            {
                                _pipeClient.EndWrite(ar);
                                if (ShinePipeDebugEvent != null)
                                {
                                    ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"客户端管道 成功 发送：" + ar.AsyncState.ToString() });
                                }
                            }
                            catch
                            {
                                //管道释放时，会导致异步结束出错
                            }
                        }
                    }, p_msg);
            }
            else
            {
                if (ShinePipeDebugEvent != null)
                {
                    ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"服务器管道 发送 失败，管道不存在或已经关闭" });
                }
            }
    }

        /// <summary>
        /// 连接服务器
        /// </summary>
        private bool Connect()
        {
            try
            {
                if (ShinePipeDebugEvent != null)
                {
                    ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"客户端管道 连接..." });
                }
                _pipeClient.Connect(CONNECT_TIMEOUT);//超时时间限制
                if (ShinePipeDebugEvent != null)
                {
                    ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"客户端管道 成功 连接" });
                }
                return true;
            }
            catch
            {
                if (ShinePipeDebugEvent != null)
                {
                    ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"客户端管道 失败 连接" });
                }
                return false;
            }
        }

        /// <summary>
        /// 开始异步读
        /// </summary>
        private void ReadWork()
        {
            if (_pipeClient != null && _pipeClient.IsConnected)
            {
                if (ShinePipeDebugEvent != null)
                {
                    ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"客户端管道准备接收。。。" });
                }

                byte[] byteArray = new byte[1024];
                _pipeClient.BeginRead(byteArray, 0, byteArray.Length,
                    ar =>
                    {
                        if (ar.IsCompleted)
                        {
                            try
                            {
                                _pipeClient.EndRead(ar);
                                byte[] content = ar.AsyncState as byte[];
                                string strTmp = System.Text.Encoding.Unicode.GetString(content).Replace('\0', ' ').Trim();
                                if (ShinePipeDebugEvent != null)
                                {
                                    ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"客户端管道 成功 接收：" + strTmp });
                                }

                                if (strTmp == @"NamePipeCloseRes")
                                {
                                    Dispose();
                                    return;
                                }

                                if (strTmp == @"NamePipeCloseReq")
                                {
                                    Write(@"NamePipeCloseRes");
                                    Thread.Sleep(100);
                                    Dispose();
                                    return;
                                }

                                if (ShinePipeRecvEvent != null)
                                {
                                    ShinePipeRecvEvent(this, new ShinePipeRecvEventArgs() { Message = strTmp });
                                }

                                ReadWork();
                            }
                            catch
                            {
                                //管道释放时，会导致异步结束出错
                            }
                        }

                    },
                    byteArray);
            }
            else
            {
                if (ShinePipeDebugEvent != null)
                {
                    ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"客户端管道接收失败，管道不存在或已关闭" });
                }
            }
        }
    }
}
